﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using ecdl.demo.model.expression;
using System.Text.RegularExpressions;
using DocumentFormat.OpenXml;
using DocumentFormat.OpenXml.Wordprocessing;
using DocumentFormat.OpenXml.Packaging;
using System.Xml;
using System.Xml.Serialization;

namespace ecdl.demo.model.expression {
    public class WordBookmarkRegexExpression : Expression {
        private static readonly string INVALID_CONTEXT = "Die WordBookmark-Bedingung kann nur innerhalb eines WordContext-Tags verwendet werden.";
        private static readonly string CAUSE_POS = "Der erwartete Text konnte gefunden werden";
        private static readonly string CAUSE_NEG = "Der erwartete Text konnte nicht gefunden werden.";

        public WordBookmarkRegexExpression() {
        }

        public WordBookmarkRegexExpression(string regex, string bookmark) {
            Bookmark = bookmark;
            RegexPattern = regex;
        }

        public string Bookmark { get; set; }

        public string RegexPattern { get; set; }

        public override ExpressionState Evaluate(ExpressionContext context) {
            if (context.HasContext<WordprocessingDocument>()) {
                WordprocessingDocument document = context.GetContext<WordprocessingDocument>();

                BookmarkStart bookmark = GetBookmark(Bookmark, document);

                string bookmarkText = getAllTextInBookmark(bookmark);
                if (Regex.IsMatch(bookmarkText, RegexPattern)) {
                    return Success(CAUSE_POS, CAUSE_NEG);
                } else {
                    return Fail(CAUSE_POS, CAUSE_NEG);
                }
            } else {
                return Fail(INVALID_CONTEXT);
            }
        }

        private string getAllTextInBookmark(BookmarkStart bookmark) {
            StringBuilder builder = new StringBuilder();

            OpenXmlElement currentElement = bookmark;
            if (bookmark != null) {
                while ((currentElement = currentElement.NextSibling<Run>()) != null) {
                    foreach (var text in currentElement.Where(x => x is Text)) {
                        builder.Append(text.InnerText);
                    }
                }
            }
            return builder.ToString();
        }

        private BookmarkStart GetBookmark(string name, WordprocessingDocument document) {
            IEnumerable<BookmarkStart> bookmarks = document.MainDocumentPart.RootElement.Descendants<BookmarkStart>();

            //there should be only one bookmark with the given name
            return bookmarks.FirstOrDefault(bookmark => bookmark.Name.InnerText.Equals(name));
        }
    }

    public class WordBookmarkRegexExpressionDTO : ExpressionDTO {
        public WordBookmarkRegexExpressionDTO() :base(typeof(WordBookmarkRegexExpression)) {

        }

        public WordBookmarkRegexExpressionDTO(string bookmark, string regex) {
            Bookmark = bookmark;
            RegexPattern = regex;
        }

        [XmlAttribute("bookmark")]
        public string Bookmark { get; set; }
        
        [XmlAttribute("regex")]
        public string RegexPattern { get; set; }

    }
}
